package allinpay

import (
    "fmt"
	"time"
	"sort"
	"strconv"
	"strings"
	"io/ioutil"
	"net/http"
	"net/url"
	"math/rand"
	"crypto/md5"
	"encoding/xml"
	"thirdpaysdk/utils/mapstruct"
	"github.com/astaxie/beego"
)

type Auth struct {
	requrl     string
	appsecret  string
}

func NewSDK(restURL, appsecret string) *Auth {
	return &Auth{requrl:restURL, appsecret:appsecret}
}

func (this *Auth) Request(request,response interface{}) ([]byte, error) {
	params := mapstruct.Struct2Map(request, "form")
	params["sign"] = makeSign(params, this.appsecret)
	urlParams := url.Values{}
	for k, v := range params {
		urlParams.Add(k, fmt.Sprintf("%v", v))
	}
	body := strings.NewReader(urlParams.Encode())
	reqHttp, err := http.NewRequest("POST", this.requrl, body)
	if err != nil {
		return nil, err
	}
	reqHttp.Header.Set("Content-Type", "application/x-www-form-urlencoded") //必须
	client := &http.Client{}
	resp, err := client.Do(reqHttp)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	beego.Debug("rsp data:", string(data))
	err = xml.Unmarshal(data, &response)
	if err != nil {
	    return nil, err
	}	
	return data, nil
}

// 产生随机字符串
func getNonceStr(n int) string {
	chars := []byte("abcdefghijklmnopqrstuvwxyz0123456789")
	value := []byte{}
	m := len(chars)
	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	for i := 0; i < n; i++ {
		value = append(value, chars[r.Intn(m)])
	}

	return string(value)
}

func makeSign(params map[string]interface{}, key string) string {
	paramsNew := make(map[string]string)
	for k, v := range params {
		if s, ok := v.(string); ok {
			paramsNew[k] = s
		} else if _, ok := v.(int); ok {
			paramsNew[k] = strconv.Itoa(v.(int))
		} else if _, ok := v.(float64); ok {
			paramsNew[k] = strconv.FormatFloat(v.(float64), 'f', -1, 32)
		} else {
			beego.Debug("map格式错误,key,value:", k, v)
		}
	}
	paramsNew["key"] = key
	var keys []string
	var sorted []string
	for k, v := range paramsNew {
		if k != "sign" && v != "" {
			keys = append(keys, k)
		}
	}
	sort.Strings(keys)
	for _, k := range keys {
		sorted = append(sorted, fmt.Sprintf("%s=%s", k, paramsNew[k]))
	}
	str := strings.Join(sorted, "&")
	return fmt.Sprintf("%X", md5.Sum([]byte(str)))
}
